package com.smart.oil.service.impl;


import com.smart.oil.constants.Constant;
import com.smart.oil.entity.SmPermission;
import com.smart.oil.exception.BusinessException;
import com.smart.oil.exception.code.BaseResponseCode;
import com.smart.oil.mapper.SmPermissionMapper;
import com.smart.oil.service.PermissionService;
import com.smart.oil.service.RedisService;
import com.smart.oil.service.RolePermissionService;
import com.smart.oil.service.UserRoleService;
import com.smart.oil.utils.TokenSettings;
import com.smart.oil.vo.req.PermissionAddReqVO;
import com.smart.oil.vo.req.PermissionUpdateReqVO;
import com.smart.oil.vo.resp.PermissionRespNodeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: PermissionServiceImpl
 * TODO:类文件简单描述
 * @Author: 杨鑫鑫
 * @UpdateUser: 杨鑫鑫
 * @Version: 0.0.1
 */
@SuppressWarnings("ALL")
@Service
@Slf4j
public class PermissionServiceImpl implements PermissionService {
    @Autowired
    private SmPermissionMapper smPermissionMapper;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TokenSettings tokenSettings;
    @Override
    public List<SmPermission> selectAll() {
        List<SmPermission> smPermissions = smPermissionMapper.selectAll();
        if(!smPermissions.isEmpty()){
            for (SmPermission smPermission :
                    smPermissions) {
                SmPermission parent = smPermissionMapper.selectByPrimaryKey(smPermission.getPid());
                if(parent!=null){
                    smPermission.setPidName(parent.getName());
                }
            }
        }
        return smPermissions;
    }

    @Override
    public List<PermissionRespNodeVO> selectAllMenuByTree() {
        List<SmPermission> list=smPermissionMapper.selectAll();
        List<PermissionRespNodeVO> result=new ArrayList<>();
        PermissionRespNodeVO respNodeVO=new PermissionRespNodeVO();
        respNodeVO.setId("0");
        respNodeVO.setTitle("智慧油田应用技术平台");
        respNodeVO.setChildren(getTree(list,true));
        result.add(respNodeVO);
        return result;
    }
    /**
     * type=true 递归遍历到菜单
     * type=false 递归遍历到按钮
     * @Author:      杨鑫鑫
     * @UpdateUser:
     * @Version:     0.0.1
     * @param all
     * @param type
     * @return       java.util.List<com.smart.oil.vo.resp.PermissionRespNodeVO>
     * @throws
     */
    private List<PermissionRespNodeVO> getTree(List<SmPermission> all,boolean type){

        List<PermissionRespNodeVO> list=new ArrayList<>();
        if(all==null||all.isEmpty()){
            return list;
        }
        for(SmPermission smPermission:all){
            if(smPermission.getPid().equals("0")){
                PermissionRespNodeVO respNodeVO=new PermissionRespNodeVO();
                BeanUtils.copyProperties(smPermission,respNodeVO);
                respNodeVO.setTitle(smPermission.getName());
                if(type){
                    respNodeVO.setChildren(getChildExBtn(smPermission.getId(),all));
                }else {
                    respNodeVO.setChildren(getChild(smPermission.getId(),all));
                }

                list.add(respNodeVO);
            }
        }
        return list;
    }
    /**
     * 递归遍历所有数据
     * @Author:      杨鑫鑫
     * @UpdateUser:
     * @Version:     0.0.1
     * @param id
     * @param all
     * @return       java.util.List<com.smart.oil.vo.resp.PermissionRespNodeVO>
     * @throws
     */
    private List<PermissionRespNodeVO> getChild(String id,List<SmPermission> all){

        List<PermissionRespNodeVO> list=new ArrayList<>();
        for (SmPermission s:
                all) {
            if(s.getPid().equals(id)){
                PermissionRespNodeVO respNodeVO=new PermissionRespNodeVO();
                BeanUtils.copyProperties(s,respNodeVO);
                respNodeVO.setTitle(s.getName());
                respNodeVO.setChildren(getChild(s.getId(),all));
                list.add(respNodeVO);
            }
        }
        return list;
    }
    /**
     * 只递归到菜单
     * @Author:      杨鑫鑫
     * @UpdateUser:
     * @Version:     0.0.1
     * @param id
     * @param all
     * @return       java.util.List<com.smart.oil.vo.resp.PermissionRespNodeVO>
     * @throws
     */
    private List<PermissionRespNodeVO> getChildExBtn(String id,List<SmPermission> all){
        List<PermissionRespNodeVO> list=new ArrayList<>();
        for (SmPermission s:
             all) {
            if(s.getPid().equals(id)&&s.getType()!=3){
                PermissionRespNodeVO respNodeVO=new PermissionRespNodeVO();
                BeanUtils.copyProperties(s,respNodeVO);
                respNodeVO.setTitle(s.getName());
                respNodeVO.setChildren(getChildExBtn(s.getId(),all));
                list.add(respNodeVO);
            }
        }
        return list;
    }

    @Override
    public SmPermission addPermission(PermissionAddReqVO vo) {
        SmPermission smPermission=new SmPermission();
        BeanUtils.copyProperties(vo,smPermission);
        verifyForm(smPermission);
        smPermission.setId(UUID.randomUUID().toString());
        smPermission.setCreateTime(new Date());
        int insert = smPermissionMapper.insertSelective(smPermission);
        if(insert!=1){
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        return smPermission;
    }
    /**
     * - 操作后的菜单类型是目录的时候 父级必须为目录
     * - 操作后的菜单类型是菜单的时候，父类必须为目录类型
     * - 操作后的菜单类型是按钮的时候 父类必须为菜单类型
     * @Author:      杨鑫鑫
     * @UpdateUser:
     * @Version:     0.0.1
     * @param smPermission
     * @return       void
     * @throws
     */
    private void verifyForm(SmPermission smPermission){

        SmPermission parent=smPermissionMapper.selectByPrimaryKey(smPermission.getPid());
        switch (smPermission.getType()){
            case 1:
                if(parent!=null){
                    if(parent.getType()!=1){
                        throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                    }
                }else if (!smPermission.getPid().equals("0")){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                }
                break;
            case 2:
                if(parent==null||parent.getType()!=1){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_MENU_ERROR);
                }
                if(StringUtils.isEmpty(smPermission.getUrl())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                break;
            case 3:
                if(parent==null||parent.getType()!=2){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_BTN_ERROR);
                }
                if(StringUtils.isEmpty(smPermission.getPerms())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_PERMS_NULL);
                }
                if(StringUtils.isEmpty(smPermission.getUrl())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                if(StringUtils.isEmpty(smPermission.getMethod())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_METHOD_NULL);
                }
                if(StringUtils.isEmpty(smPermission.getCode())){
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_CODE_NULL);
                }
                break;
        }
    }

    @Override
    public List<PermissionRespNodeVO> permissionTreeList(String userId) {
        List<SmPermission> list=getPermission(userId);
        return getTree(list,true);
    }

    @Override
    public List<PermissionRespNodeVO> selectAllTree() {
        return getTree(selectAll(),false);
    }

    @Override
    public void updatePermission(PermissionUpdateReqVO vo) {
        //校验数据
        SmPermission update=new SmPermission();
        BeanUtils.copyProperties(vo,update);
        verifyForm(update);
        SmPermission smPermission = smPermissionMapper.selectByPrimaryKey(vo.getId());
        if(smPermission==null){
            log.info("传入的id在数据库中不存在");
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        if(!smPermission.getPid().equals(vo.getPid())){
            //所属菜单发生了变化要校验该权限是否存在子集
            List<SmPermission> smPermissions = smPermissionMapper.selectChild(vo.getId());
            if(!smPermissions.isEmpty()){
                throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_UPDATE);
            }
        }

        update.setUpdateTime(new Date());
        int i = smPermissionMapper.updateByPrimaryKeySelective(update);
        if(i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }

        //判断授权标识符是否发生了变化
        if(!smPermission.getPerms().equals(vo.getPerms())){
            List<String> roleIdsByPermissionId = rolePermissionService.getRoleIdsByPermissionId(vo.getId());
            if(!roleIdsByPermissionId.isEmpty()){
                List<String> userIdsByRoleIds = userRoleService.getUserIdsByRoleIds(roleIdsByPermissionId);
                if(!userIdsByRoleIds.isEmpty()){
                    for (String userId:
                         userIdsByRoleIds) {
                        redisService.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSettings.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
                        /**
                         * 清楚用户授权数据缓存
                         */
                        redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
                    }
                }
            }

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletedPermission(String permissionId) {
        //判断是否有子集关联
        List<SmPermission> smPermissions = smPermissionMapper.selectChild(permissionId);
        if(!smPermissions.isEmpty()){
            throw new BusinessException(BaseResponseCode.ROLE_PERMISSION_RELATION);
        }
        //解除相关角色和该菜单权限的关联
        rolePermissionService.removeRoleByPermissionId(permissionId);
        //更新权限数据
        SmPermission smPermission=new SmPermission();
        smPermission.setUpdateTime(new Date());
        smPermission.setDeleted(0);
        smPermission.setId(permissionId);
        int i = smPermissionMapper.updateByPrimaryKeySelective(smPermission);
        if(i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //判断授权标识符是否发生了变化
        List<String> roleIdsByPermissionId = rolePermissionService.getRoleIdsByPermissionId(permissionId);
        if(!roleIdsByPermissionId.isEmpty()){
            List<String> userIdsByRoleIds = userRoleService.getUserIdsByRoleIds(roleIdsByPermissionId);
            if(!userIdsByRoleIds.isEmpty()){
                for (String userId:
                        userIdsByRoleIds) {
                    redisService.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSettings.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
                    /**
                     * 清楚用户授权数据缓存
                     */
                    redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
                }
            }
        }
    }

    @Override
    public Set<String> getPermissionsByUserId(String userId) {

        List<SmPermission> list=getPermission(userId);
        Set<String> permissions=new HashSet<>();
        if (null==list||list.isEmpty()){
            return null;
        }
        for (SmPermission smPermission:list){
            if(!StringUtils.isEmpty(smPermission.getPerms())){
                permissions.add(smPermission.getPerms());
            }

        }
        return permissions;
    }

    @Override
    public List<SmPermission> getPermission(String userId) {
        List<String> roleIds = userRoleService.getRoleIdsByUserId(userId);
        if(roleIds.isEmpty()){
            return null;
        }
        List<String> permissionIds= rolePermissionService.getPermissionIdsByRoles(roleIds);
        if (permissionIds.isEmpty()){
            return null;
        }
        List<SmPermission> result=smPermissionMapper.selectInfoByIds(permissionIds);
        return result;
    }
}
